/**
 * Crea la classe che si occupera` di gestire le risposte dei DS
 * @param {Object} sourcesNumber Indica quanti DS dovra` aspettarsi la classe
 */


function ResponseHandler(sourcesNumber,callback)
{

	/** Indica se la classe è pronta ad erogare il suo servizio */
	this.isready = false;
	
	/** Indica se è in corso l'eleborazione XSLT */
	this.isrunning = false;
	
	/** Funzione da chiamare al termine della fase di inizializzazione */	
	//VARIABILI PRIVATE
	var OriginalDOM;
	var TransformedDOM;
	
	var WindowSize=10;
	var ResponsesNumber;
	var ResponseArray = new Array();
	
	var xslStyleSheet = "http://ltw0807.web.cs.unibo.it/al/sort.xsl";
	var xsl;
	var toTransform = false;
	
	var SortingField1 = null;
	var SortingField2 = null;
	var SortingAscending = null;
	
	var respErr=new Array();
	var deviScremareRevisioni=false;
	var painkiller = "http://ltw0807.web.cs.unibo.it/al/painkiller.xsl";
	var xslpain;
	
	/**
	 * Salva una risposta ottenuta dal data source
	 * @param {Object} source Document da aggiungere come risposta
	 */
	this.addSource = function(source){
		//Controlla che gli errori siano generati da tutti i DS, nel caso crea l'errore
		//unificato altrimenti se ci sono risultati vengono ignorati gli errori
		if (source.getElementsByTagName("ds:errore").length != 0)
			respErr.push(source);
		else
			ResponseArray.push(source);
			
		if (respErr.length==sourcesNumber) {
			ironMerger(mergeErrors(respErr));
			return;
		}
		if (ResponseArray.length + respErr.length == sourcesNumber) {
			OriginalDOM = merge(ResponseArray);
			if (!toTransform) 
				toTransform = true;
			else 
				this.initialize();
		}
	}
	
	/**
	 * Restituisce un documento DOM contenente la le risposte nella finestra specificata
	 * NB: Dal momento che lo schema di XSLT non mi permette di parametrizzare il sorting
	 * order, siamo costretti ad applicarlo qui
	 * @param {Integer} index Indice della finestra interessata (parte da 0)
	 * @return {DOM} Restituisce un nuovo documento DOM contenente la risposta
	 */
	this.getWindow = function(index)
	{
		var responseDOM = createDOM("response");
		for(var i=WindowSize*index; i<WindowSize*(index+1); i++){
			if ((i >= 0) && (i < ResponsesNumber)) {
				var elem = TransformedDOM.getElementsByTagName('metadati')[i];
				if (elem != null) 
					responseDOM.documentElement.appendChild(responseDOM.importNode(elem, true));
			}
		}
		return responseDOM;
	}
	
	/**
	 * @return {Integer} Ritorna la dimensione della finestra
	 */
	this.getWinNum = function(){
		return WindowSize;
	}
	
	/**
	 * @return {Integer} Ritorna il numero complessivo dei risultati
	 */
	this.getResNum = function(){
		return ResponsesNumber;
	}
	
	/**
	 * Setta la larghezza della finestra
	 * @param {Integer} num Nuova larghezza
	 */
	this.setWinSize = function(num){
		WindowSize = num;
	}
	
	/**
	 * Calcola il numero di Window
	 * @return {Object} Ritorna il numero di Window
	 */
	this.getWindowsNumber = function(){
		var winNum = (ResponsesNumber / WindowSize);
		winNum = Math.floor(winNum);
		if (ResponsesNumber % WindowSize != 0)
			winNum ++;
		return winNum;
	}
	
	
	/**
	 * Fa il merge dei response ritornati dai DS
	 * 
	 * Da controllare che il risultato sia uno in modo da ritornare una scheda nel caso
	 * 
	 * @param {Object} array Array dei documenti nudi e crudi tornati dal DS
	 * @return {DOM} Ritorna il documento DOM ottenuto
	 */
	var merge = function(array){
		var newDOM = createDOM("response","");
		for (var i=0; i<array.length; i++){
			for (var j=0; j < array[i].documentElement.childNodes.length; j++) {
				var nodo = array[i].documentElement.childNodes[j];
				if (nodo.nodeName == "metadati")
					newDOM.firstChild.appendChild(newDOM.importNode(nodo, true));
			}
		}
		return newDOM;
	}
	
	/**
	 * Conta quanti elementi ha la risposta passata in input
	 * @param {DOM} originalDom Documento DOM di cui controllare i tag "metadati"
	 * @return {Integer} Numero di "metadati"
	 */
	var count = function(originalDom){
		return originalDom.getElementsByTagName('metadati').length;
	}
	
	/**
	 * Funzione di test
	 * @param {Object} nodo
	 */
	var nodeInfo = function(nodo){
		alert("nome: " + nodo.nodeName + "\ntipo: " + nodo.nodeType + "\nfigli: " + nodo.childNodes.length);
	}

	/**
	 * Modifica l'xsl passato in input in base alle variabili globali
	 * @param {Object} targetXsl xsl da modificare
	 */
	var updateXsl = function(targetXsl){
		if (SortingField1 != null){
			var parameters = targetXsl.getElementsByTagName('param');
			/**
			 * funzioncina di comodo che modifica i parametri dell'xsl
			 * @param {Object} field Campo in esame
			 * @param {Object} paramIndex Indice all'interno dell'array di parametri
			 */
			var selectSortField = function(field,paramIndex){
				switch (field) {
					case "edate":
						parameters[paramIndex].setAttribute('select', 'expression/edate');
						break;
					case "etype":
						parameters[paramIndex].setAttribute('select', 'expression/etype');
						break;
				}
			}
			
			
			for(var i=0; i<parameters.length; i++){
				if (parameters[i].getAttribute('name').value == "SortingField1")
					selectSortField(SortingField1, i);
				if (parameters[i].getAttribute('name').value == "SortingField2")
					if (SortingField2 != null) 
						selectSortField(SortingField2, i);
			}
		}
		
	}
	
	this.useScrema=function(value){
		deviScremareRevisioni=value;
	}
	
	/**
	 * Una volta entrato in possesso di tutti gli elementi, inizializza la struttura
	 * ed esegue l'ordinamento prima e la scrematura delle revisioni se richiesto
	 */
	this.initialize = function(){
		this.isrunning = true;
		this.isready = false;
		//tutta sta roba va tolta ricordiamoci!
		//updateXsl(xsl);
		
		TransformedDOM = xslTransform(OriginalDOM,xsl,null);
		if(deviScremareRevisioni==true){
			var aj= new AjaxManager(painkiller, null, 
			function(hr){
				xslpain=hr.responseXML; 
				TransformedDOM = xslTransform(TransformedDOM,xslpain,null);
				finalize();
			}, 
			function(){alert("Impossibile reperire:\n" + painkiller);}
			)
			aj.get();
		}else
			finalize();
	}
	
	/**
	 * Svolte gli ultimi compiti dopo le trasfomrazioni xsl al risultato
	 */
	function finalize(){
		ResponsesNumber = count(TransformedDOM);
		this.isready = true;
		this.isrunning = false;
		callback();
	}
	/**
	 * Modifica i parametri di ordinamento
	 * @param {Object} field1 Primo campo su cui ordinare
	 * @param {Object} field2 Secondo campo su cui ordinare (eventualmente null)
	 * @param {Object} ascending True per un ordinamento ascendente, false per uno discendente
	 * @return {Object} Restituisce true se l'operazione è andata a buon fine, false nel caso in
	 * cui i parametri siano sbagliati o il momento sia inopportuno (please, try later)
	 */
	this.setSortingField = function(field1,field2,ascending)
	{
		if (!checkField(field1)) return false;
		if (!checkField(field2)) return false;
		if (this.isrunning) return false;
		
		SortingField1 = field1;
		SortingField2 = field2;
		SortingAscending = ascending;
		if (!this.isready)
			initialize();
		return true;
		
	}
	
	/**
	 * Controlla se il campo è un campo ammesso
	 * @param {Object} field Nome del campo
	 * @return {Object} Ritorna true nel caso il campo si gradito al ResponseHandler
	 */
	var checkField = function(field)
	{
		if (field == "edate") return true;
		if (field == "etype") return true;
		else return false;
	}
	
	
	//Costruttore

	var am= new AjaxManager(xslStyleSheet, null, 
			function(hr){
				xsl=hr.responseXML; 
				if (toTransform) 
					this.initialize();
				else 
					toTransform = true;
			}, 
			function(){alert("Impossibile reperire:\n" + xslStyleSheet + "\nMolto male...");}
	)
	am.get();
}
